package com.ccrfid.rmc6.service.business.prison.rollcall;

import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.business.prison.rollcall.PrisonRollcallPlaceEntity;
import com.ccrfid.rmc6.entity.business.prison.rollcall.PrisonRollcallPlacePersonnelRelation;
import com.ccrfid.rmc6.entity.personnel.PersonnelView;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.pojo.dto.prison.rollcall.PrisonRollcallPersonnelDto;
import com.ccrfid.rmc6.repository.business.prison.rollcall.PrisonRollcallPlacePersonnelRepository;
import com.ccrfid.rmc6.repository.business.prison.rollcall.PrisonRollcallPlaceRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelViewRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;

@Service
@Transactional
public class PrisonRollcallPlaceServiceImpl implements PrisonRollcallPlaceService {
    private static final Logger logger = LoggerFactory.getLogger(PrisonRollcallPlaceServiceImpl.class);

    @Autowired
    private PrisonRollcallPlaceRepository rollcallPlaceRepository;
    @Autowired
    private PrisonRollcallPlacePersonnelRepository rollcallPlacePersonnelRepository;
    @Autowired
    private PersonnelViewRepository personnelViewRepository;

    @Override
    public List<PrisonRollcallPlaceEntity> getRollcallPlaceList() {
        return rollcallPlaceRepository.getAllBy();
    }

    @Override
    public PrisonRollcallPlaceEntity getRollcallPlace(Long placeId) {
        return rollcallPlaceRepository.getById(placeId);
    }

    @Override
    public PrisonRollcallPlaceEntity createRollcallPlace(PrisonRollcallPlaceEntity entity) throws AppException {

        checkParam(entity);

        return rollcallPlaceRepository.save(entity);
    }

    private void checkParam(PrisonRollcallPlaceEntity entity) throws AppException {
        if (entity.getPlaceName() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.place_name_is_null.getCode(), CustomErrors.place_name_is_null.getReason(), "");
        }
        if (entity.getNodeType() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.node_type_is_null.getCode(), CustomErrors.node_type_is_null.getReason(), "");
        }
        if (entity.getPid() != null) {
            PrisonRollcallPlaceEntity parentNode = rollcallPlaceRepository.getById(entity.getPid());
            if (parentNode == null) {
                //1.父节点不存在
                throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                        CustomErrors.pid_not_found.getCode(), CustomErrors.pid_not_found.getReason(), "");
            } else {
                //2.父节点不是目录类型
                if (!parentNode.getNodeType().equals(Constants.NODE_TYPE.CATALOG.id)) {
                    throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                            CustomErrors.parent_node_not_catalog.getCode(), CustomErrors.parent_node_not_catalog.getReason(), "");
                }
            }
        }
    }

    @Override
    public PrisonRollcallPlaceEntity updateRollcallPlace(Long placeId, PrisonRollcallPlaceEntity entity) throws AppException {
        if (!rollcallPlaceRepository.existsById(placeId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (!placeId.equals(entity.getId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        checkParam(entity);

        return rollcallPlaceRepository.save(entity);
    }

    @Override
    public Boolean deleteRollcallPlace(Long placeId) {
        deleteNodeAndSubNodes(placeId);
        return true;
    }

    //递归删除节点和子节点
    private void deleteNodeAndSubNodes(Long placeId) {
        if (rollcallPlaceRepository.existsByPid(placeId)) {
            //1.删除子节点
            List<PrisonRollcallPlaceEntity> subList = rollcallPlaceRepository.getAllByPid(placeId);
            for (PrisonRollcallPlaceEntity sub : subList) {
                deleteNodeAndSubNodes(sub.getId());
            }
            //2.删除自己
            rollcallPlaceRepository.deleteById(placeId);
        } else {
            //删除自己
            rollcallPlaceRepository.deleteById(placeId);
        }
    }

    @Override
    public Boolean deleteRollcallPlaceList(List<Long> idList) {
        for (Long id : idList) {
            if (rollcallPlaceRepository.existsById(id)) {
                deleteNodeAndSubNodes(id);
            }
        }
        return true;
    }

    @Override
    public List<PrisonRollcallPersonnelDto> getRollcallPlacePersonnelList(Long placeId) {
        List<PrisonRollcallPlacePersonnelRelation> relationList = rollcallPlacePersonnelRepository.getAllByPlaceId(placeId);
        if (relationList != null && relationList.size() > 0) {
            List<Long> personnelIdList = new ArrayList<>();
            for (PrisonRollcallPlacePersonnelRelation relation : relationList) {
                personnelIdList.add(relation.getPersonnelId());
            }
            List<PersonnelView> personnelViewList = personnelViewRepository.getAllByIdIn(personnelIdList);
            if (personnelViewList != null && personnelViewList.size() > 0) {
                List<PrisonRollcallPersonnelDto> resultList = new ArrayList<>();
                for (PersonnelView personnelView : personnelViewList) {
                    PrisonRollcallPersonnelDto personnelDto =
                            new PrisonRollcallPersonnelDto(personnelView.getId(), personnelView.getPersonnelSn(),
                                    personnelView.getPersonnelName(), personnelView.getCardNumber(),
                                    personnelView.getOrgId(), personnelView.getOrgName());
                    resultList.add(personnelDto);
                }
                return resultList;
            } else {
                return new ArrayList<>();
            }
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public List<Long> getRollcallPlacePersonnelIdList(Long placeId) {
        List<PrisonRollcallPlacePersonnelRelation> relationList = rollcallPlacePersonnelRepository.getAllByPlaceId(placeId);
        if (relationList != null && relationList.size() > 0) {
            List<Long> personnelIdList = new ArrayList<>();
            for (PrisonRollcallPlacePersonnelRelation relation : relationList) {
                personnelIdList.add(relation.getPersonnelId());
            }
            return personnelIdList;
        } else {
            return null;
        }
    }

    @Override
    public Boolean updateRollcallPlacePersonnelList(Long placeId, List<Long> newPersonnelIdList) throws AppException {
        if (!rollcallPlaceRepository.existsById(placeId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (newPersonnelIdList == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.param_is_null.getCode(), CustomErrors.param_is_null.getReason(), "");
        }
        List<PrisonRollcallPlacePersonnelRelation> relationList = rollcallPlacePersonnelRepository.getAllByPlaceId(placeId);
        if (relationList != null && relationList.size() > 0) {
            List<Long> originalPersonnelIdList = new ArrayList<>();
            for (PrisonRollcallPlacePersonnelRelation relation : relationList) {
                originalPersonnelIdList.add(relation.getPersonnelId());
            }
            //1.删除新关系中没有的旧关系
            for (Long personnelId : originalPersonnelIdList) {
                if (!newPersonnelIdList.contains(personnelId)) {
                    rollcallPlacePersonnelRepository.deleteByPlaceIdAndPersonnelId(placeId, personnelId);
                }
            }
            //2.添加旧关系中没有的新关系
            for (Long personnelId : newPersonnelIdList) {
                if (!originalPersonnelIdList.contains(personnelId)) {
                    createRollcallPlacePersonnelRelation(placeId, personnelId);
                }
            }
        } else {
            //没有旧关系时，直接创建新关系
            for (Long personnelId : newPersonnelIdList) {
                createRollcallPlacePersonnelRelation(placeId, personnelId);
            }
        }
        return true;
    }

    private void createRollcallPlacePersonnelRelation(Long placeId, Long personnelId) {
        PrisonRollcallPlacePersonnelRelation relation = new PrisonRollcallPlacePersonnelRelation();
        relation.setPlaceId(placeId);
        relation.setPersonnelId(personnelId);
        rollcallPlacePersonnelRepository.save(relation);
    }

    @Override
    public Boolean createRollcallPlacePersonnelList(Long placeId, List<Long> personnelIdList) throws AppException {
        if (!rollcallPlaceRepository.existsById(placeId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (personnelIdList == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.param_is_null.getCode(), CustomErrors.param_is_null.getReason(), "");
        }
        for (Long personnelId : personnelIdList) {
            if (!rollcallPlacePersonnelRepository.existsByPlaceIdAndPersonnelId(placeId, personnelId)) {
                createRollcallPlacePersonnelRelation(placeId, personnelId);
            }
        }
        return true;
    }

    @Override
    public Boolean deleteRollcallPlacePersonnel(Long placeId, Long personnelId) throws AppException {
        if (!rollcallPlaceRepository.existsById(placeId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (rollcallPlacePersonnelRepository.existsByPlaceIdAndPersonnelId(placeId, personnelId)) {
            rollcallPlacePersonnelRepository.deleteByPlaceIdAndPersonnelId(placeId, personnelId);
        }
        return true;
    }

    @Override
    public Boolean deleteRollcallPlacePersonnelList(Long placeId, List<Long> personnelIdList) throws AppException {
        if (!rollcallPlaceRepository.existsById(placeId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (personnelIdList == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.param_is_null.getCode(), CustomErrors.param_is_null.getReason(), "");
        }
        for (Long personnelId : personnelIdList) {
            if (rollcallPlacePersonnelRepository.existsByPlaceIdAndPersonnelId(placeId, personnelId)) {
                rollcallPlacePersonnelRepository.deleteByPlaceIdAndPersonnelId(placeId, personnelId);
            }
        }
        return true;
    }

    @Override
    public List<PersonnelView> getRollcallPlaceFreePersonnelsInOrg(Long placeId, Long orgId) {
        List<Long> personnelIdList = getRollcallPlacePersonnelIdList(placeId);
        if (personnelIdList != null && personnelIdList.size() > 0) {
            return personnelViewRepository.getAllByOrgIdAndEnabledAndIdNotIn(orgId, 1, personnelIdList);
        } else {
            return personnelViewRepository.getAllByOrgIdAndEnabled(orgId, 1);
        }
    }
}
